package com.cwh.taskcenter.notice.gateway;

import com.alibaba.fastjson.JSON;
import com.cwh.taskcenter.domain.notice.gateway.TaskNotificationGateWay;
import com.cwh.taskcenter.domain.notice.model.AdvancedConfig;
import com.cwh.taskcenter.domain.notice.model.ChannelType;
import com.cwh.taskcenter.domain.notice.model.NotifyTrigger;
import com.cwh.taskcenter.domain.notice.model.TaskNotification;
import com.cwh.taskcenter.domain.notice.model.TaskNotificationChannel;
import com.cwh.taskcenter.domain.notice.model.TriggerType;
import com.cwh.taskcenter.notice.dto.ChannelConfigDTO;
import com.cwh.taskcenter.notice.email.dto.EmailConfigDTO;
import com.cwh.taskcenter.notice.inbox.dto.InboxConfigDTO;
import com.cwh.taskcenter.notice.mapper.NotificationChannelConfigMapper;
import com.cwh.taskcenter.notice.mapper.TaskNotificationRuleMapper;
import com.cwh.taskcenter.notice.model.NotificationChannelConfigDO;
import com.cwh.taskcenter.notice.model.TaskNotificationRuleDO;
import com.cwh.taskcenter.notice.popup.dto.PopupConfigDTO;
import com.cwh.taskcenter.notice.sms.dto.SmsConfigDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

/**
 * @author cwh
 */
@Slf4j
@Repository
@RequiredArgsConstructor
public class TaskNotificationGateWayImpl implements TaskNotificationGateWay {

    @Autowired
    private TaskNotificationRuleMapper taskNotificationRuleMapper;

    @Autowired
    private NotificationChannelConfigMapper notificationChannelConfigMapper;


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void save(TaskNotification taskNotification) {

        if (taskNotification == null) return;

        Long taskId = taskNotification.getTaskId();
        NotifyTrigger rule = taskNotification.getNotifyTrigger();
        AdvancedConfig advanced = taskNotification.getAdvanced();

        // 1. 保存通知规则（带空指针检查）
        if (rule != null) {
            saveNotificationRule(taskId, rule, advanced);
        }

        // 2. 保存渠道配置
        saveChannelConfigs(taskNotification);
    }

    @Override
    public TaskNotification findByTaskId(Long taskId) {
        TaskNotification taskNotification = new TaskNotification();
        taskNotification.setTaskId(taskId);

        // 1. 组装通知规则
        List<TaskNotificationRuleDO> ruleDOList = taskNotificationRuleMapper.findByTaskId(taskId);
        NotifyTrigger notifyTrigger = new NotifyTrigger();
        AdvancedConfig advancedConfig = new AdvancedConfig();

        for (TaskNotificationRuleDO ruleDO : ruleDOList) {
            TriggerType triggerType = TriggerType.fromCode(ruleDO.getTriggerType());
            if (triggerType == null) continue;

            switch (triggerType) {
                case TASK_EXPIRING:
                    notifyTrigger.setExpire(true);
                    notifyTrigger.setExpireAdvance(ruleDO.getExpireAdvanceHours());
                    break;
                case TASK_COMPLETION:
                    notifyTrigger.setComplete(true);
                    break;
                case REWARD_GRANT:
                    notifyTrigger.setReward(true);
                    break;
            }

            // 高级配置（频率）只取一次，因为所有规则共享
            if (ruleDO.getFrequencyMinute() != null) {
                advancedConfig.setFrequency(ruleDO.getFrequencyMinute());
            }
        }
        taskNotification.setNotifyTrigger(notifyTrigger);
        taskNotification.setAdvanced(advancedConfig);

        // 2. 组装渠道配置
        List<NotificationChannelConfigDO> channelConfigs = notificationChannelConfigMapper.findByTaskId(taskId);
        TaskNotificationChannel channels = new TaskNotificationChannel();
        List<ChannelConfigDTO> channelConfigList = new ArrayList<>();
        for (NotificationChannelConfigDO configDO : channelConfigs) {
            ChannelType channelType = ChannelType.fromCode(configDO.getChannelType());
            if (channelType == null) continue;

            switch (channelType) {
                case SMS:
                    SmsConfigDTO smsConfig = JSON.parseObject(configDO.getConfigJson(), SmsConfigDTO.class);
                    smsConfig.setChannelType(channelType.getCode());
                    channels.setSms(smsConfig);
                    channelConfigList.add(smsConfig);
                    break;
                case POPUP:
                    PopupConfigDTO popupConfig = JSON.parseObject(configDO.getConfigJson(), PopupConfigDTO.class);
                    popupConfig.setChannelType(channelType.getCode());
                    channels.setPopup(popupConfig);
                    channelConfigList.add(popupConfig);
                    break;
                case EMAIL:
                    EmailConfigDTO emailConfig = JSON.parseObject(configDO.getConfigJson(), EmailConfigDTO.class);
                    emailConfig.setChannelType(channelType.getCode());
                    channels.setEmail(emailConfig);
                    channelConfigList.add(emailConfig);
                    break;
                case INBOX:
                    InboxConfigDTO inboxConfig = JSON.parseObject(configDO.getConfigJson(), InboxConfigDTO.class);
                    inboxConfig.setChannelType(channelType.getCode());
                    channels.setInbox(inboxConfig);
                    channelConfigList.add(inboxConfig);
                    break;
            }
        }
        taskNotification.setChannels(channels);
        taskNotification.setChannelConfigs(channelConfigList);

        return taskNotification;
    }

    private void saveNotificationRule(Long taskId, NotifyTrigger rule, AdvancedConfig advanced) {
        List<TaskNotificationRuleDO> taskNotificationRuleDOList = new ArrayList<>();

        if (rule.isExpire()) {
            taskNotificationRuleDOList.add(createAndSaveRule(taskId, TriggerType.TASK_EXPIRING, rule.getExpireAdvance(), advanced));
        }
        if (rule.isComplete()) {
            taskNotificationRuleDOList.add(createAndSaveRule(taskId, TriggerType.TASK_COMPLETION, rule.getExpireAdvance(), advanced));
        }
        if (rule.isReward()) {
            taskNotificationRuleDOList.add(createAndSaveRule(taskId, TriggerType.REWARD_GRANT, rule.getExpireAdvance(), advanced));
        }
        taskNotificationRuleMapper.creates(taskNotificationRuleDOList);
    }

    private TaskNotificationRuleDO createAndSaveRule(Long taskId, TriggerType triggerType, Integer expireAdvance, AdvancedConfig advanced) {
        TaskNotificationRuleDO ruleDO = new TaskNotificationRuleDO();
        ruleDO.setTaskId(taskId);
        ruleDO.setTriggerType(triggerType.getCode());
        if (expireAdvance != null) {
            ruleDO.setExpireAdvanceHours(expireAdvance); // 仅对过期通知设置
        }
        if (advanced != null) {
            ruleDO.setFrequencyMinute(advanced.getFrequency());
        }
        return ruleDO;
    }

    private void saveChannelConfigs(TaskNotification taskNotification) {
        List<NotificationChannelConfigDO> channelConfigs = new ArrayList<>();
        TaskNotificationChannel channels = taskNotification.getChannels();
        if (channels == null) {
            return;
        }

        if (channels.getSms() != null && channels.getSms().getEnable()) {
            channelConfigs.add(saveSingleChannelConfig(taskNotification.getTaskId(), channels.getSms(), ChannelType.SMS));
        }

        if (channels.getPopup() != null && channels.getPopup().getEnable()) {
            channelConfigs.add(saveSingleChannelConfig(taskNotification.getTaskId(), channels.getPopup(), ChannelType.POPUP));
        }

        if (channels.getEmail() != null && channels.getEmail().getEnable()) {
            channelConfigs.add(saveSingleChannelConfig(taskNotification.getTaskId(), channels.getEmail(), ChannelType.EMAIL));
        }

        if (channels.getInbox() != null && channels.getInbox().getEnable()) {
            channelConfigs.add(saveSingleChannelConfig(taskNotification.getTaskId(), channels.getInbox(), ChannelType.INBOX));
        }

        notificationChannelConfigMapper.creates(channelConfigs);
    }

    private NotificationChannelConfigDO saveSingleChannelConfig(Long taskId, ChannelConfigDTO config, ChannelType channelType) {
        NotificationChannelConfigDO configDO = new NotificationChannelConfigDO();
        configDO.setTaskId(taskId);
        configDO.setChannelType(channelType.getCode());
        configDO.setConfigJson(JSON.toJSONString(config));
        return configDO;
    }

}
